package com.anhry.app.ansafety.service.realm;


import net.sf.json.JSONObject;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.cas.CasAuthenticationException;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.cas.CasToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.CollectionUtils;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@SuppressWarnings("deprecation")
public class MzCasRealm extends CasRealm {


    @Autowired
    private CacheManager cacheManager;
  
    public MzCasRealm() {  
        super();  
        setCacheManager(cacheManager);  
    }  

    /**
     * 授权访问控制，用于对用户进行的操作进行人证授权，证明该用户是否允许进行当前操作，如访问某个链接，某个资源文件等
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		//获取当前登录的用户名
		String account = (String) super.getAvailablePrincipal(principals);

		if(null==account||"".equals(account)){
			throw new AuthorizationException();
		}
		return info;
    	}

    /**
     * 验证用户身份
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    	CasToken casToken = (CasToken) token;  
        if (token == null)  
            return null;  
        String ticket = (String) casToken.getCredentials();  
        if (null==ticket||"".equals(ticket)){
            return null;  
        }
        TicketValidator ticketValidator = ensureTicketValidator();
        try {
            Assertion casAssertion = ticketValidator.validate(ticket, getCasService());
            AttributePrincipal casPrincipal = casAssertion.getPrincipal();
            String userId = URLDecoder.decode(casPrincipal.getName(),"UTF-8");
            System.out.println("Validate ticket : {"+ticket+"} in CAS server : {"+getCasServerUrlPrefix()+"} to retrieve user : {"+userId+"}");
            Map<String,Object> attributes = new HashMap<String,Object>();  
            

            if(isJSONValid(userId)){
                JSONObject jsonObject = JSONObject.fromObject(userId);
                String sutype=jsonObject.getString("usertype");
            	userId=jsonObject.getString("username");
            	attributes.put("usertype",sutype);
            }else{
            	attributes = casPrincipal.getAttributes(); 
            }  
            casToken.setUserId(userId);  
            String rememberMeAttributeName = getRememberMeAttributeName();  
            String rememberMeStringValue = (String) attributes.get(rememberMeAttributeName);  
            boolean isRemembered = rememberMeStringValue != null && Boolean.parseBoolean(rememberMeStringValue);  
            if (isRemembered)  
                casToken.setRememberMe(true);  
            List principals = CollectionUtils.asList(new Object[] { userId, attributes });
            PrincipalCollection principalCollection = new SimplePrincipalCollection(principals, getName());
  
            // 这里可以拿到Cas的登录账号信息,加载到对应权限体系信息放到缓存中...
    		if (userId != null&&!"".equals(userId)) {
    			// 要放在作用域中的东西，请在这里进行操作
    			//存放当前登录用户的单位名称、部门名称、子部门名称
    			setSession("username", userId);

    			return new SimpleAuthenticationInfo(principalCollection, ticket);
    		} else {
    			return null;
    		}
        } catch (TicketValidationException e) {
            System.out.println("Unable to validate ticket ["+(ticket)+("]"));
            throw new CasAuthenticationException((new StringBuilder()).append("Unable to validate ticket [")  
                    .append(ticket).append("]").toString(), e);  
        } catch (UnsupportedEncodingException e) {
            System.out.println(e.getMessage());
		}
		return null;  
	
    }

    @Override
    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    @Override
    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    @Override
    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }

    public void clearAllCachedKickoutInfo() {

    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
        clearAllCachedKickoutInfo();
    }
    
    private void setSession(Object key, Object value){  
        Subject currentUser = SecurityUtils.getSubject();
        if(null != currentUser){  
            Session session = currentUser.getSession();
            System.out.println("Session默认超时时间为[" + session.getTimeout() + "]毫秒");
            if(null != session){  
                session.setAttribute(key, value);  
            }  
        }  
    }  
	
    public final static boolean isJSONValid(String test) {
        try {
            JSONObject.fromObject(test);
        } catch (Exception ex) {
                return false;
        }
        return true;
    }
  
}
